#pragma once
#include <string.h>
#include <iostream>
namespace JRG {

class string {
public:
	//friend std::ostream& operator<<(std::ostream & out, const string & s);
	typedef char* iterator;
	typedef const char* const_iterator;
	string(const char* str = "") {
		_a = new char[strlen(str)+16];
		strcpy(_a, str);
		_size = strlen(str);
		_capacity = strlen(str) + 16;
	}
	string(const string& s) {
		_a = new char[s._capacity];
		strcpy(_a, s._a);
		_size = s._size;
		_capacity = s._capacity;
	}
	string& operator=(const string& s) {
		_a = new char[s._capacity];
		strcpy(_a, s._a);
		_size = s._size;
		_capacity = s._capacity;
		return *this;
	}
	~string() {
		delete[] _a;
		_size = _capacity = 0;
	}

	iterator begin() {
		return _a;
	}
	const_iterator begin() const{
		return _a;
	}
	iterator end() {
		return _a + _size;
	}
	const_iterator end() const{
		return _a + _size;
	}
	void push_back(char c) {
		if (_size+1 >= _capacity) {
			reserve(2 * _capacity);
		}
		_a[_size] = c;
		_size++;
		_a[_size] = '\0';
	}

	string& operator+=(char c) {
		push_back(c);
		return *this;
	}

	void append(const char* str) {
		if (_size + strlen(str) > _capacity) {
			reserve(2 * _capacity);
		}
		strcpy(_a + _size, str);
		_size += strlen(str);
	}

	string& operator+=(const char* str) {
		append(str);
		return *this;
	}
	void clear() {
		_a[0] = '\0';
		_size = 0;
	}
	void swap(string& s) 
	{
		std::swap(_a, s._a);
		std::swap(_size, s._size);
		std::swap(_capacity, s._capacity);
	}
	const char* c_str()const 
	{
		return _a;
	}

	size_t size()const
	{
		return _size;
	}
	size_t capacity()const
	{
		return _capacity;
	}
	bool empty()const
	{
		return _size == 0;
	}
	char& operator[](size_t index) {
		return _a[index];
	}
	const char& operator[](size_t index) const{
		return _a[index];
	}

	bool operator<(const string& s) {
		return strcmp(_a, s._a) < 0;
	}
	bool operator<=(const string& s) {
		return *this < s || *this == s;
	}
	bool operator>(const string& s) {
		return strcmp(_a, s._a) > 0;
	}
	bool operator>=(const string& s) {
		return *this > s || *this == s;
	}
	bool operator==(const string& s) {
		return strcmp(_a, s._a) == 0;
	}
	bool operator!=(const string& s) {
		return !(*this == s);
	}
	size_t find(char c, size_t pos = 0)const {
		while (pos < _size) {
			if (c == _a[pos])
				return pos;
			pos++;
		}
		return npos;
	}
	size_t find(const char* s, size_t pos = 0) {
		return strstr(_a, s)-begin();
	}
	string& insert(size_t pos, char c) {
		if (_size >= _capacity)
			reserve(2 * _capacity);
		size_t next = _size+1;
		while (next > pos) {
			_a[next] = _a[next-1];
			--next;
		}
		_a[next] = c;
		_size++;
		return *this;
	}
	string& insert(const char* s, size_t pos) 
	{
		int len = strlen(s);
		if (_size + len >= _capacity) {
			reserve(_size + len + 1);
		}
		size_t next = _size+len;
		while (next >= pos+len) {
			_a[next] = _a[next-len];
			--next;
		}
		strncpy(_a + pos, s,len);
		_size += len;
		return *this;

	}
	string& erase(size_t pos, size_t len=npos) {
		int next = pos + len;
		if (len == npos) {
			_a[pos] = '\0';
			_size = pos;
		
		}
		else {
			/*while (next <= _size) {
				_a[next - len] = _a[next];
				next++;
			}*/
			strcpy(_a + pos, _a + pos + len);
			_size -= len;
		}
		
		return *this;
	}
	void resize(size_t n, char c = '\0') {
		if (n < _size) {
			_a[n] = '\0';
			_size = n;
		}
		else {
			if (n > _capacity)
				reserve(n);
			memset(_a + _size+1, c, n - _size-2);
		}
	}
	void reserve(size_t n) {
		if (n > _capacity) {
			char* tem = new char[n];
			strcpy(tem, _a);
			delete[] _a;
			_a = tem;
			_capacity = n;
		}
	}
	

private:
	char* _a;
	size_t _size;
	size_t _capacity;
	static const size_t npos;
};
const size_t string::npos = -1;

	std::ostream& operator<<(std::ostream& out, const string& s)
	{
		for (auto ch : s) {
			out << ch;
		}
		return out;
	}

	std::istream& operator>>(std::istream& in, string& s) {
		s.clear();
		char ch = in.get();
		char buff[128];
		size_t i = 0;
		while (ch != ' ' && ch != '\n') {
			buff[i++] = ch;
			if (i == 127) {
				buff[127] = '\0';
				s += buff;
				i = 0;
			}
			ch = in.get();
		}
		if (buff != 0) {
			buff[i] = '\0';
			s += buff;
		}
		return in;
	}
}